'use strict';

const fs = require('fs');
const { get } = require('lodash');
const path = require('path');
const _ = require('lodash');
const assert = require('assert');
const { logger } = require('../misc/logger');
const { Decrypt, Encrypt } = require('./secret');
let config;

/**
 * 格式化数字
 * @param {*} number
 * @param {*} precision
 * @param {*} separator
 */
exports.formatNumber = function (number, precision = 2, separator = ',') {
	if ((!number || !_.trim(number)) && number !== 0 && number !== '0') {
		number = 0;
	}

	if (!precision && precision !== 0) {
		precision = 2;
	}

	if (!separator) {
		separator = ',';
	}

	if (number === Infinity) {
		number = 0;
	}

	let parts;
	if (!isNaN(parseFloat(number)) && isFinite(number)) {
		number = Number(Number(number).toFixed(4));
		number = (typeof precision !== 'undefined' ? number.toFixed(precision) : number).toString();
		// 分离数字的小数部分和整数部分
		parts = number.split('.');
		// 整数部分加[separator]分隔
		parts[0] = parts[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + separator);

		return parts.join('.');
	}

	return null;
}

/**
 *
 * @param num
 * @constructor
 */
exports.toNumber = function (num) {
	return isNaN(Number(num)) ? 0 : Number(Number(num).toFixed(4));
}

const getConfig = function () {
	if (config) {
		return config;
	}

	logger.log('Load config file');
	try {
		const argv = process.argv;
		let property = '';
		if (argv[2] === '-P' || argv[2] === '-p' || argv[2] === '-property') {
			property = !!argv[3] ? '.' + argv[3] : '';
		}

		if (fs.existsSync(path.join(process.cwd(), `config${property}.9cc`))) {
			config = fs.readFileSync(path.join(process.cwd(), `config${property}.9cc`)).toString();
			config = JSON.parse(Decrypt(config));
			logger.log(typeof config, 'config type');
		} else {
			config = JSON.parse(fs.readFileSync(path.join(process.cwd(), `config${property}.json`)));
		}
	} catch (e) {
		logger.error('this software won\'t run without a valid config file');
		logger.error(e);
		process.exit(1);
	}

	return config;
};

exports.getConfig = getConfig;

exports.setConfig = function (configData, resort) {
	const folder = process.cwd();
	const files = [
		path.join(folder, 'config.9cc'),
		path.join(folder, `config.${resort}.9cc`),
		path.join(folder, 'config.json'),
		path.join(folder, `config.${resort}.json`),
	];

	for (const file of files) {
		if (fs.existsSync(file)) {
			if (/\.9cc$/.test(file)) {
				let data = Encrypt(JSON.stringify(configData));// 加密

				fs.writeFileSync(file, data);
				if (data !== fs.readFileSync(file, 'utf8')) {
					throw new Error('Configuration set error. Reason unknown');
				}
			} else {
				fs.writeFileSync(file, JSON.stringify(configData, null, '\t'));
			}
		}
	}
};

exports.WEEKDAY = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; // 0 周日, 6 周六

exports.sleep = (ms) => new Promise(function (resolve, reject) {
	setTimeout(() => {
		resolve(true);
	}, ms);
});

exports.generateTransactionId = function() {
	return parseInt(Math.random().toString().replace('.', '').substring(0, 6));
}

exports.isEmpty = function(value) {
	return value === undefined || value === '' || value === null
}

exports.validConfig = function() {
	const v = getConfig();

	const resort = get(v, 'resort', '');
	const cardType = get(v, 'cardType', '');
	const chainCode = get(v, 'ows.chainCode', '');
	const username = get(v, 'ows.username', '');
	const password = get(v, 'ows.password', '');
	const stationID = get(v, 'ows.stationID', '');
	const OriginEntityID = get(v, 'ows.origin.entityID', '');
	const OriginSystemType = get(v, 'ows.origin.systemType', '');
	const DestinationEntityID = get(v, 'ows.destination.entityID', '');
	const DestinationSystemType = get(v, 'ows.destination.systemType', '');

	assert(resort, 'Invalid interface config > resort');
	assert(cardType, 'Invalid interface config > cardType');
	assert(chainCode, 'Invalid interface config > ows > chainCode');
	assert(username, 'Invalid interface config > ows > username');
	assert(password, 'Invalid interface config > ows > password');
	assert(stationID, 'Invalid interface config > ows > stationID');
	assert(OriginEntityID, 'Invalid interface config > ows > origin > entityID');
	assert(OriginSystemType, 'Invalid interface config > ows > origin > systemType');
	assert(DestinationEntityID, 'Invalid interface config > ows > destination > entityID');
	assert(DestinationSystemType, 'Invalid interface config > ows > destination > systemType');

	return {
		resort,
		chainCode,
		username,
		password,
		stationID,
		cardType,
		OriginEntityID,
		OriginSystemType,
		DestinationEntityID,
		DestinationSystemType
	}
}